package start.spring.basic.job.quartz;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import start.spring.basic.dynamic.SpringJdbc;
import start.spring.basic.util.common.StringUtil;

/**
 * ****************************************************************************
 * 自动任务运行时操作类
 *
 * @author(作者)：xuyongyun	
 * @date(创建日期)：2018年8月30日
 ******************************************************************************
 */
@Slf4j
@Configuration
@Service
public class TaskService {
	
	@Resource(name = "scheduler")
	private Scheduler scheduler;
	
	@Autowired
	private SpringJdbc dao;
	
	/**     
     * 查询数据库配置任务列表
     *  
     * @return     
     */
	public List<TaskBean> getTaskFromDb(){
        List<TaskBean> jobs = new ArrayList<TaskBean>();
        try {
        	String sql = "select * from GG_PZ_JOB t ";
        	List<Map<String, Object>> resultList = this.dao.query(sql,null);
            if(resultList!=null&&resultList.size()>0){
            	for(int i=0;i<resultList.size();i++){
            		
            		Map<String, Object> tmpMap = (Map<String, Object>) resultList.get(i);
            		String jobClass = StringUtil.trimObject(tmpMap.get("JOBCLASS"),null);
            		
            		TaskBean job = new TaskBean();
            		job.setJobName(StringUtil.trimObject(tmpMap.get("JOBCLASS"),null));
            		job.setJobGroup(StringUtil.trimObject(tmpMap.get("TRIGGERGROUP"),null));
            		job.setDescription(StringUtil.trimObject(tmpMap.get("DESCRIPTION"),null));
            		job.setCronTime(StringUtil.trimObject(tmpMap.get("CRONTIME"),null));
            		job.setJobClass(jobClass);
            		job.setThreadNum(Integer.parseInt(StringUtil.trimObject(tmpMap.get("THREADNUM"),"1")));
            		job.setTimeOut(Integer.parseInt(StringUtil.trimObject(tmpMap.get("TIMEOUT"),"30")));
            		job.setYxbz(StringUtil.trimObject(tmpMap.get("YXBZ"),"Y"));
            		job.setSfbf(StringUtil.trimObject(tmpMap.get("SFBF"),"N"));
            		
            		jobs.add(job);
            	}
            }
        }catch(Exception e) {
        	log.error("",e);
        }
        return jobs;
    }
	
	/**
	 * 添加一个任务到Scheduler，不包括数据库
	 * 
	 * @param task 任务明细
	 * 
	 * @throws SchedulerException
	 * @throws ClassNotFoundException 任务对应job不存在
	 */
    @SuppressWarnings("unchecked")
	public void addJob(TaskBean task) throws SchedulerException, ClassNotFoundException {  
       
    	boolean isJobExit = isJobExist(task);
    	
    	if(isJobExit) {
    		//任务已经存在，更新任务
    		updateJob(task);
		
    	}else {
    		//任务不存在，创建任务
    		String jobclass = task.getJobClass();
            JobDetail jobDetail = JobBuilder
            				.newJob((Class<? extends Job>) Class.forName(jobclass))  
                            .withIdentity(task.getJobName(), task.getJobGroup())
                            .withDescription(task.getDescription())
                            .build();
            
            jobDetail.getJobDataMap().put(QuartzConstant.THREAD_NUM, task.getThreadNum());
            jobDetail.getJobDataMap().put(QuartzConstant.TIME_OUT, task.getTimeOut());
            jobDetail.getJobDataMap().put(QuartzConstant.YXBZ, task.getYxbz());
            jobDetail.getJobDataMap().put(QuartzConstant.SFBF, task.getSfbf());
            
            //job的执行计划
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(
            		task.getCronTime());
            
            //job触发器
            CronTrigger trigger = TriggerBuilder.newTrigger()
            		.withIdentity(task.getJobName(), task.getJobGroup())
            		.withDescription(task.getDescription())
            		.withSchedule(scheduleBuilder).build();

            //执行任务
            scheduler.scheduleJob(jobDetail, trigger);
    	}
        
    }
    
    /**
     * 立即执行Scheduler一个任务
     * 
     * @param task 任务明细
     * 
     * @throws SchedulerException
     */      
    public void runJob(TaskBean task) throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());     
        scheduler.triggerJob(jobKey);      
    }
      
    /**
     * 暂停Scheduler中任务
     * 
     * @param task 任务明细
     * 
     * @throws SchedulerException
     */
    public void pauseJob(TaskBean task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
        scheduler.pauseJob(jobKey);
    }
      
    /**
     * 暂停Scheduler中所有任务
     * 
     * @throws SchedulerException
     */ 
    public void pauseAllJob() throws SchedulerException {
        scheduler.pauseAll();  
    }  
      
    /**
     * 恢复Scheduler中任务
     * 
     * @param task 任务明细
     * 
     * @throws SchedulerException
     */
    public void resumeJob(TaskBean task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());  
        scheduler.resumeJob(jobKey);
    }  
      
    /**
     * 恢复Scheduler中所有任务
     * 
     * @throws SchedulerException
     */ 
    public void resumeAllJob() throws SchedulerException {
        scheduler.resumeAll();  
    }  
      
    /**
     * 删除Scheduler中任务，不包括数据库中信息删除
     * 
     * @param task 任务明细
     * 
     * @throws SchedulerException
     */
    public void delJob(TaskBean task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());  
        scheduler.deleteJob(jobKey);  
    }  
    
    /**
     * 批量删除除Scheduler中任务，不包括数据库中信息删除
     * 
     * @param taskList 需要删除的任务列表
     * 
     * @throws SchedulerException
     */
    public void delJobs(List<TaskBean> taskList) throws SchedulerException {
        List<JobKey> jobKeyList = new ArrayList<JobKey>();  
        for(TaskBean task:taskList) {
            JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());  
            jobKeyList.add(jobKey);  
        }  
        scheduler.deleteJobs(jobKeyList);  
    }
    
    /**
     * 删除所有job
     * @throws SchedulerException
     */
    public void delAllJob() throws SchedulerException{
    	List<TaskBean> jobs = getAllJobs();
        if(jobs!=null){
        	for(TaskBean job:jobs){
				if(job!=null){
					delJob(job);
				}
			}
        }
   }
    
    /**     
     * 更新任务
     * 
     * @throws SchedulerException
     */
    public void updateJob(TaskBean task) throws SchedulerException{
    	TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getJobGroup()); 
    	
        //job的执行计划
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(
        		task.getCronTime());
        
        //job触发器
        CronTrigger trigger = TriggerBuilder.newTrigger()
        		.withIdentity(task.getJobName(), task.getJobGroup())
        		.withDescription(task.getDescription())
        		.withSchedule(scheduleBuilder).build();
        
        //按新的trigger重新设置job执行      
        scheduler.rescheduleJob(triggerKey, trigger);
    }
    
    /**
     * Scheduler中任务是否存在，不包括数据库中信息删除
     * 
     * @param task 任务明细
     * 
     * @return
     * @throws SchedulerException
     */
    public boolean isJobExist(TaskBean task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());  
        return scheduler.checkExists(jobKey);
    }
    
    /**
     * 获取Scheduler中任务运行状态
     * 
     * @param task 任务明细
     * 
     * @return
     * 		None：Trigger已经完成，且不会再执行，或者找不到该触发器，或者Trigger已经被删除  
     *		NORMAL:正常状态
     *		PAUSED：暂停状态   
     *	    COMPLETE：触发器完成，但是任务可能还正在执行中
     *		ERROR：出现错误
     *      BLOCKED：线程阻塞状态
     *      
     * @throws SchedulerException
     */
    public String getJobState(TaskBean task) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getJobGroup());
        return scheduler.getTriggerState(triggerKey).name().toString();
    }
    
    /**
     * 获取Scheduler中任务运行状态
     * 
     * @param jobClass 任务类名
     * 
     * @return
     * 		None：Trigger已经完成，且不会再执行，或者找不到该触发器，或者Trigger已经被删除  
     *		NORMAL:正常状态
     *		PAUSED：暂停状态   
     *	    COMPLETE：触发器完成，但是任务可能还正在执行中
     *		ERROR：出现错误
     *      BLOCKED：线程阻塞状态
     *      
     * @throws SchedulerException
     */
    public String getJobState(String jobClass) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobClass, jobClass);
        return scheduler.getTriggerState(triggerKey).name().toString();
    }
    
    /**     
     * 获取Scheduler中指定任务
     * 
     * @param jobName  任务名
     * @param jobGroup 任务组名
     * @return     
     * @throws SchedulerException     
     */      
    public TaskBean getJob(TaskBean task) throws SchedulerException{
    	TaskBean job = null;
    	JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
        List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
        if (null != triggers&&triggers.size()>0) {
        	Trigger trigger = triggers.get(0);
            job = new TaskBean();
            job.setDescription(trigger.getDescription());
            job.setStartTime(trigger.getStartTime());
            
            //下次触发时间 
            job.setNextTime(trigger.getNextFireTime()); 
            
            //上次触发时间
            job.setPreviousTime(trigger.getPreviousFireTime());
            
            job.setTriggerStatus(getJobState(task));
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpression = cronTrigger.getCronExpression();
                job.setCronTime(cronExpression);
            }
        }
        return job;
    }
    
    /**     
     * 获取Scheduler中指定任务
     * 
     * @param jobName  任务名
     * @param jobGroup 任务组名
     * @return     
     * @throws SchedulerException     
     */      
    public TaskBean getJob(String jobClass) throws SchedulerException{
    	TaskBean job = null;
    	JobKey jobKey = JobKey.jobKey(jobClass, jobClass);
        List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
        if (null != triggers&&triggers.size()>0) {
        	Trigger trigger = triggers.get(0);
            job = new TaskBean();
            job.setDescription(trigger.getDescription());
            job.setStartTime(trigger.getStartTime());
            
            //下次触发时间 
            job.setNextTime(trigger.getNextFireTime()); 
            
            //上次触发时间
            job.setPreviousTime(trigger.getPreviousFireTime());
            
            job.setTriggerStatus(getJobState(jobClass));
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpression = cronTrigger.getCronExpression();
                job.setCronTime(cronExpression);
            }
        }
        return job;
    }
    
    /**     
     * 获取Scheduler中所有任务
     *   
     * @return
     * @throws SchedulerException
     */      
    public List<TaskBean> getAllJobs() throws SchedulerException{
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);      
        List<TaskBean> jobList = new ArrayList<TaskBean>();      
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);      
            if (null != triggers&&triggers.size()>0) {
            	Trigger trigger = triggers.get(0);
            	TaskBean job = new TaskBean();
            	job.setJobName(jobKey.getName());
            	job.setJobClass(jobKey.getClass().getName());
            	job.setJobGroup(jobKey.getGroup());
            	job.setDescription(trigger.getDescription());
                job.setStartTime(trigger.getStartTime());
                
                //下次触发时间 
                job.setNextTime(trigger.getNextFireTime()); 
                
                //上次触发时间
                job.setPreviousTime(trigger.getPreviousFireTime());
                
                job.setTriggerStatus(getJobState(job));
                job.setTriggerStatusName(this.getJobStatusName(job.getTriggerStatus()));
                
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    job.setCronTime(cronExpression);
                }
                jobList.add(job);
            }
        }
        return jobList;
    }
    
    /**     
     * 获取Scheduler中所有正在运行的job
     *      
     * @return     
     * @throws SchedulerException     
     */      
    public List<TaskBean> getRunningJob() throws SchedulerException {
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();      
        List<TaskBean> jobList = new ArrayList<TaskBean>(executingJobs.size());      
        for (JobExecutionContext executingJob : executingJobs) {      
        	TaskBean job = new TaskBean();      
            JobDetail jobDetail = executingJob.getJobDetail();      
            JobKey jobKey = jobDetail.getKey();      
            Trigger trigger = executingJob.getTrigger();
            job.setJobName(jobKey.getName());
            job.setJobGroup(jobKey.getGroup());
            job.setDescription(trigger.getDescription());
            job.setTriggerStatus(getJobState(job));
            if (trigger instanceof CronTrigger) {      
            	CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpression = cronTrigger.getCronExpression();
                job.setCronTime(cronExpression);      
            }
            jobList.add(job);
        }
        return jobList;
    }
    
    /**
     * 校验cron表达式是否正确
     * 
     * @param cronExpression
     * 
     * @return
     * @throws ParseException
     */
    public boolean isExpressionValid(String cronExpression){       

    	CronTriggerImpl trigger = new CronTriggerImpl();          
        try {       
            trigger.setCronExpression(cronExpression);       
            Date date = trigger.computeFirstFireTime(null);         
            return (date != null && date.after(new Date()));          
        }catch(ParseException e) {  
        	log.error("",e);
        }        
        return false;    
    }

    /**
     * 获取job的当前状态
     * 
     * @param jobStatus
     * @return
     */
    private String getJobStatusName(String jobStatus) {
    	JSONObject statusJob = new JSONObject();
    	statusJob.put("None", "停止");
    	statusJob.put("NORMAL", "正常");
    	statusJob.put("PAUSED", "暂停");
    	statusJob.put("COMPLETE", "已触发");
    	statusJob.put("ERROR", "出错");
    	statusJob.put("BLOCKED", "线程阻塞");
    	String jobStatusName = statusJob.getString(jobStatus);
    	if(StringUtil.isEmpty(jobStatus)) {
    		jobStatusName = "未知";
    	}
    	return jobStatusName;
    }
    
}
